import math

True, False = 1, 0

def ifelse(condition, true_value, false_value):
        if condition:
                return true_value
        else:
                return false_value

def degreesToRadians(degrees):
        return degrees*math.pi/180

def radiansToDegrees(radians):
        return radians * 180 / math.pi
               
class PwVector(object):
        __slots__ = ("x", "y", "z")
        def __init__(self, *args):
                if len(args) > 1:
                        self.x, self.y, self.z = args[0], args[1], args[2]
                else:
                        matrix = args[0]
                        self.x, self.y, self.z = matrix.get(0,0), matrix.get(1,0), matrix.get(2,0)
        def __add__(self, other):
                if isinstance(other, PwVector):
                        return PwVector(self.x + other.x, self.y + other.y, self.z + other.z)
                else:
                        return PwVector(self.x + other, self.y + other, self.z + other)
        def __sub__(self, other):
                return self + -other
        def __mul__(self, other):
                return PwVector(self.x * other, self.y * other, self.z * other)
        def __rmul__(self, other):
                return self * other
        def __div__(self, other):
                return PwVector(self.x / other, self.y / other, self.z / other)
        def __rdiv__(self, other):
                return self / other
        def __neg__(self):
                return PwVector(-self.x, -self.y, -self.y)
        def __str__(self):
                return "Vector " + str( (self.x, self.y, self.z) )
        def __len__(self):
                return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
        def length(self):
                return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z)
        def normalize(self):
                lensq = self.x*self.x + self.y*self.y + self.z*self.z
                if( lensq == 0 ):
                        return self
                else:
                        recip = 1/self.length()
                        return PwVector(self.x*recip, self.y*recip, self.z*recip)
        def dot(self, other):
                return self.x*other.x + self.y*other.y + self.z*other.z
        def cross(self, other):
                return PwVector(self.y*other.z - other.y*self.z, self.z*other.x - other.z*self.x, self.x*other.y - other.x*self.y)
        def matrix(self):
                return PwMatrix( [self.x], [self.y], [self.z], [0] )

class PwPoint(object):
        __slots__ = ("x", "y", "z")
        def __init__(self, *args):
                if len(args) > 1:
                        self.x, self.y, self.z = args[0], args[1], args[2]
                elif isinstance(args[0], PwMatrix):
                        matrix = args[0]
                        self.x, self.y, self.z = matrix.get(0,0), matrix.get(1,0), matrix.get(2,0)
                else:
                        self.x, self.y, self.z = args[0]
        def __mul__(self, other):
                return PwPoint(self.x * other, self.y * other, self.z * other)
        def __rmul__(self, other):
                return self * other
        def __add__(self, other):
                return PwPoint(self.x+other.x, self.y+other.y, self.z+other.z)
        def __sub__(self, other):
                return PwVector(self.x-other.x, self.y-other.y, self.z-other.z)
        def __str__(self):
                return "Point " + str( (self.x, self.y, self.z) )
        def dist(self, other):
                x = self.x - other.x
                y = self.y - other.y
                z = self.z - other.z
                return math.sqrt(x*x + y*y + z*z)
        def matrix(self):
                return PwMatrix( [self.x], [self.y], [self.z], [1] )
        def blend(self, other, v):
                w = 1.0 - v
                return v * self + w * other

def PwPlane(object):
        def __init__(self, p0, p1, p2):
                self.origin = P
                radius = size/2
                p0 = P + PwVector(radius, radius, 0)
                p1 = P + PwVector(-radius, radius, 0)
                p2 = P + PwVector(-radius, -radius, 0)
                p3 = P + PwVector(radius, -radius, 0)
                self.A = p0.y*(p1.z-p2.z) + p1.y*(p2.z-p0.z) + p2.y*(p0.z-p1.z)
                self.B = p0.z*(p1.x-p2.x) + p1.z*(p2.x-p0.x) + p2.z*(p0.x-p1.x)
                self.C = p0.x*(p1.y-p2.y) + p0.x*(p2.y-p0.y) + p2.x*(p0.y-p1.y)
                self.D = -p0.x*(p1.y*p2.z - p2.y*p1.z)  +\
                         -p1.x*(p2.y*p0.z - p0.y*p2.z) +\
                         -p2.x*(p0.y*p1.z - p1.y*p0.z)
                self.N = PwVector(A,B,C)

def sum(L):
        total = 0
        for item in L:
                print item
                total = total + item
        return total

class PwMatrix(object):
        __slots__ = ("matrix")
        def __init__(self, *args):
                self.matrix = []
                for row in args:
                        self.append( row )
        def __mul__(self, other):
                if isinstance(other, PwMatrix):
                        matrix = PwMatrix()
                        rows = len(self.matrix)
                        cols = len(other.matrix[0])
                        for i in range(rows):
                                row = []
                                for j in range(cols):
                                        col = 0
                                        for k in range( len(self.matrix[i]) ):
                                                col = col + self.matrix[i][k] * other.matrix[k][j]
                                        row.append(col)
                                matrix.append(row)
                        return matrix
                elif isinstance(other, PwPoint):
                        return PwPoint( self * other.matrix() )
                elif isinstance(other, PwVector):
                        return PwVector( self * other.matrix() )
                else:
                        matrix = PwMatrix()
                        for row in self.matrix:
                                newrow = []
                                for col in row:
                                        newrow.append(col * other)
                                matrix.append(newrow)
                        return matrix
        def __rmul__(self, other):
                if isinstance(other, float) or isinstance(other, int):
                        return self * other
        def __add__(self, other):
                matrix = PwMatrix()
                for i in range(len(self.matrix)):
                        row = []
                        for j in range(len(self.matrix[0])):
                                row.append(self.matrix[i][j] + other.matrix[i][j])
                        matrix.append(row)
                return matrix
        def __sub__(self, other):
                return self + -other
        def __neg__(self):
                matrix = PwMatrix()
                for row in self.matrix:
                        newrow = []
                        for col in row:
                                newrow.append(-col)
                        matrix.append(newrow)
                return matrix
        def __str__(self):
                out = "%i x %i Matrix" % (len(self.matrix), len(self.matrix[0]))
                for row in self.matrix:
                        out += "\n" + str(row)
                return out
        def append(self, row):
                self.matrix.append(row)
        def get(self, row, col):
                return self.matrix[row][col]
        def define(self, row, col, v):
                self.matrix[row][col] = v
        def columns(self):
                return len(self.matrix[0])
        def rows(self):
                return len(self.matrix)
        def det(self):
                rows = len(self.matrix)
                if rows == 1:
                        return self.get(0,0)
                firstrow = self.matrix[0]
                cols = len(firstrow)
                tally = 0
                for i in range(cols):
                        term = firstrow[i]
                        submatrix = PwMatrix()
                        for row in range(rows):
                                if row == 0:
                                        continue
                                subrow = []
                                for col in range(cols):
                                        if col == i:
                                                continue
                                        else:
                                                subrow.append( self.get(row,col) )
                                submatrix.append(subrow)
                        result = term * submatrix.det()
                        if i == 0:
                                tally = tally + result
                        else:
                                tally = tally - result
                return tally
        def det2(self):
                return self.get(0,0)*self.get(1,1) - self.get(0,1)*self.get(1,0)
        def det3(self):
                a, b, c = self.matrix[0]
                d, e, f = self.matrix[1]
                g, h, i = self.matrix[2]
                return a*(e*i-f*h) - b*(d*i-f*g) - c*(d*h-e*g)
        def inverse(self):
                rows = len(self.matrix)
                cols = len(self.matrix[0])
                inv = PwMatrix()
                for r in range(rows):
                        newrow = []
                        for c in range(cols):
                                submatrix = PwMatrix()
                                for i in range(rows):
                                        subrow = []
                                        if i == r:
                                                continue
                                        for j in range(cols):
                                                if j == c:
                                                        continue
                                                subrow.append( self.get(i,j) )
                                        submatrix.append(subrow)
                                newrow.append( submatrix.det() )
                        inv.append(newrow)
                return inv
        def inverse2(self):
                a, b = self.matrix[0]
                c, d = self.matrix[1]
                return 1.0/(a*d-b*c) * PwMatrix([ d, -b],
                                                [-c,  a])
        def inverse3(self):
                a,b,c = self.matrix[0]
                d,e,f = self.matrix[1]
                g,h,i = self.matrix[2]
                anti = PwMatrix([ e*i-f*h,      c*h-b*i,        b*f-c*e ],
                                [ f*g-d*i,      a*i-c*g,        c*d-a*f ],
                                [ d*h-e*g,      b*g-a*h,        a*e-b*d ])
                return 1.0/self.det3() * anti
        def transpose(self):
                matrix = PwMatrix()
                for r in range(self.rows()):
                        row = []
                        for c in range(self.columns()):
                                row.append( self.get(c,r) )
                        matrix.append(row)
                return matrix

def translation(tx, ty, tz):
        return PwMatrix([1, 0, 0, tx],
                        [0, 1, 0, ty],
                        [0, 0, 1, tz],
                        [0, 0, 0, 1 ] )

def rotation(axis, degrees):
        if degrees == 0:
                return IDENTITY4x4
        theta = degrees * math.pi / 180
        c = math.cos(theta)
        s = math.sin(theta)
        t = 1 - c
        x, y, z = axis.x, axis.y, axis.z
        return PwMatrix([t*x*x+c,       t*x*y-s*z,      t*x*z+s*y,      0],
                        [t*x*y+s*z,     t*y*y+c,        t*y*z-s*x,      0],
                        [t*x*z-s*y,     t*y*z+s*x,      t*z*z+c,        0],
                        [0,             0,              0,              1])

def scale(x, y, z):
        return PwMatrix([x,0,0,0],
                        [0,y,0,0],
                        [0,0,z,0],
                        [0,0,0,1])

IDENTITY4x4 = PwMatrix( [1,0,0,0],
                        [0,1,0,0],
                        [0,0,1,0],
                        [0,0,0,1] )

IDENTITY3X3 = PwMatrix([1,0,0],
                       [0,1,0],
                       [0,0,1])

IDENTITY2X2 = PwMatrix([1,0],
                       [0,1])

ORIGIN = PwPoint(0,0,0)

XAXIS = PwVector(1,0,0)
YAXIS = PwVector(0,1,0)
ZAXIS = PwVector(0,0,1)

class PwQuaternion(object):
    def __init__(self, w, x=None, y=None, z=None):
        if w == XAXIS:
            self.w, self.x, self.y, self.z = math.cos(x)/2, math.sin(x)/2, 0, 0
        elif w == YAXIS:
            self.w, self.x, self.y, self.z = math.cos(x)/2, 0, math.sin(x)/2, 0
        elif w == ZAXIS:
            self.w, self.x, self.y, self.z = math.cos(x)/2, 0, 0, math.sin(x)/2
        elif isinstance(w, PwVector):
            self.w, self.x, self.y, self.z = 0, w.x, w.y, w.z
        elif isinstance(x, PwVector):
            self.w, self.x, self.y, self.z = w, x.x, x.y, x.z
        elif isinstance(w, tuple):
            self.w, self.x, self.y, self.z = w
        elif isinstance(x, tuple):
            self.w = w
            self.x, self.y, self.z = x
        else:
            self.w, self.x, self.y, self.z = w, x, y, z
    def __add__(self, other):
        return PwQuaternion(self.w + other.w, self.x + other.x, self.y + other.y, self.z + other.z)
    def __mul__(self, other):
        if isinstance(other, PwQuaternion):
            v1 = other.vector()
            v2 = self.vector()
            return PwQuaternion(self.w*other.w - v1.dot(v2),
                                other.w*v2 + self.w*v1 + v2.cross(v1))
        elif isinstance(other, PwVector):
                pMult = 1.0 - self.w*self.w
                vMult = 2.0 * (self.x*other.x + self.y*other.y + self.z*other.z)
                crossMult = 2.0 * self.w
                return PwVector(pMult*other.x + vMult*self.x + crossMult*(self.y*other.z - self.z*other.y),
                                pMult*other.y + vMult*self.y + crossMult*(self.z*other.x - self.x*other.z),
                                pMult*other.z + vMult*self.z + crossMult*(self.x*other.y - self.y*other.x))
        elif isinstance(other, PwPoint):
                pMult = 1.0 - self.w*self.w
                vMult = 2.0 * (self.x*other.x + self.y*other.y + self.z*other.z)
                crossMult = 2.0 * self.w
                return PwPoint(pMult*other.x + vMult*self.x + crossMult*(self.y*other.z - self.z*other.y),
                                pMult*other.y + vMult*self.y + crossMult*(self.z*other.x - self.x*other.z),
                                pMult*other.z + vMult*self.z + crossMult*(self.x*other.y - self.y*other.x))
        else:
            return PwQuaternion(self.w * other, self.x * other, self.y * other, self.z * other)
    def __rmul__(self, other):
        if isinstance(other, PwQuaternion):
            pass
        else:
            return self * other
    def __div__(self, other):
        return PwQuaternion(self.w/other, self.x/other, self.y/other, self.z/other)
    def __neg__(self):
        return PwQuaternion(-self.w, -self.x, -self.y, -self.z)
    def length(self):
        return math.sqrt(self.w*self.w + self.x*self.x + self.y*self.y + self.z*self.z)
    def __str__(self):
        return repr((self.w, self.x, self.y, self.z))
    def normalize(self):
        self = self / self.length()
        return self
    def dot(self, other):
        return self.w*other.w + self.x*other.x + self.y*other.y + self.z*other.z
    def concat(self, other):
        v1 = other.vector()
        v2 = self.vector()
        return PwQuaternion(other.w*self.w - v1.dot(v2),
                            other.w*v2 + self.w*v1 + v2.cross(v1) ).normalize()
    def reciprocal(self):
        return 1.0/self.length()**2 * PwQuaternion(self.w, -self.vector())
    def vector(self):
        return PwVector(self.x, self.y, self.z)
    def rotate(self, other):
        pmult = 1.0 - self.w*self.w
        vmult = 2.0 * (self.x*other.x + self.y*other.y + self.z*other.z)
        crossmult = 2.0 * self.w
        return PwVector( pmult*other.x + vmult*self.x + crossmult*(self.y*other.z - self.z*other.y),
                         pmult*other.y + vmult*self.y + crossmult*(self.z*other.x - self.x*other.z),
                         pmult*other.z + vmult*self.z + crossmult*(self.x*other.y - self.y*other.x) )
    def euler(self):
        return PwVector( radiansToDegrees(math.atan( 2*(self.w*self.x + self.y*self.z) / (1 - 2*(self.x*self.x + self.y*self.y)) )),
                         radiansToDegrees(math.asin( 2*(self.w*self.y + self.z*self.x) )),
                         radiansToDegrees(math.atan( 2*(self.w*self.z + self.x*self.y) / (1 - 2*(self.y*self.y + self.z*self.z)) )) )       
    def matrix(self):
        self.normalize()
        x2, y2, z2 = self.x + self.x, self.y + self.y, self.z + self.z
        xx, xy, xz = self.x * x2, self.x * y2, self.x * z2
        yy, yz, zz = self.y * y2, self.y * z2, self.z * z2
        wx, wy, wz = self.w * x2, self.w * y2, self.w * z2
        return PwMatrix([1.0 - yy - zz, xy - wz,        xz + wy,        0],
                        [xy + wz,       1.0 - xx - zz,  yz - wx,        0],
                        [xz - wy,       yz + wx,        1.0 - xx - yy,  0],
                        [0,             0,              0,              1])
                                                
class PwSpace(object):
        __slots__ = ("rotation", "translation", "transformation")
        def __init__(self, xtrans, ytrans, ztrans, xrot, yrot, zrot):
                self.translation = translation(xtrans, ytrans, ztrans)
                self.rotation = rotation(XAXIS, xrot) * rotation(YAXIS, yrot) * rotation(ZAXIS, zrot)
                self.transformation = self.translation * self.rotation
        def translate(self, point):
                return self.translation * point
        def rotate(self, point):
                return self.rotation * point
        def transform(self, point):
                return self.transformation * point

pass
